package org.openkanban.server.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dozer.DozerBeanMapper;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.openkanban.server.domain.Activity;
import org.openkanban.server.domain.Board;
import org.openkanban.server.domain.History;
import org.openkanban.server.domain.User;
import org.openkanban.server.interceptor.annotation.SecurityInterception;
import org.openkanban.server.service.ActivityService;
import org.openkanban.server.service.BoardService;
import org.openkanban.server.service.HistoryService;
import org.openkanban.server.service.UserService;
import org.openkanban.server.session.SessionAttributeHelper;
import org.openkanban.shared.dto.ActivityDto;
import org.openkanban.shared.dto.BoardDto;
import org.openkanban.shared.dto.HistoryDto;
import org.openkanban.shared.dto.StatusDto;
import org.openkanban.shared.dto.UserDto;
import org.openkanban.shared.util.StatusCodes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Controller that is responsible for all board requests. Calls corresponding
 * services to proceed.
 */
@Controller
@RequestMapping(value = "/board")
public class BoardController {

    @Autowired
    private BoardService boardService;

    @Autowired
    private UserService userService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private SessionAttributeHelper sessionAttributes;

    @Autowired
    private DozerBeanMapper mapper;

    @RequestMapping(method = RequestMethod.POST, value = "/all")
    @ResponseBody
    @SecurityInterception
    public List<BoardDto> getAllBoards(HttpServletRequest req, HttpServletResponse resp) {
	List<Board> boardList = boardService.getAll();

	List<BoardDto> boardDtoList = new ArrayList<BoardDto>();
	for (Board board : boardList) {
	    boardDtoList.add(mapper.map(board, BoardDto.class));
	}

	return boardDtoList;
    }

    @RequestMapping(method = RequestMethod.POST, value = "/{boardId}")
    @ResponseBody
    @SecurityInterception
    public BoardDto getBoardById(@PathVariable Long boardId, HttpServletRequest req, HttpServletResponse resp) {
	Board board = boardService.getBoardById(boardId);
	return mapper.map(board, BoardDto.class);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/user/{userId}")
    @ResponseBody
    @SecurityInterception
    public BoardDto getDefaultBoard(@PathVariable Long userId, HttpServletRequest req, HttpServletResponse resp) {
	Board board = boardService.getDefaultBoardByUserId(userId);
	if (board != null) {
	    return mapper.map(board, BoardDto.class);
	}
	return new BoardDto();
    }

    @RequestMapping(method = RequestMethod.POST, value = "/{currentBoardId}/{userId}/forward")
    @ResponseBody
    @SecurityInterception
    public BoardDto getDefaultBoardForward(@PathVariable Long currentBoardId, @PathVariable Long userId, HttpServletRequest req,
	    HttpServletResponse resp) {
	Long nextBoardId = boardService.getNextBoardId(currentBoardId, userId);
	BoardDto nextBoardDto = new BoardDto();
	nextBoardDto.setBoardId(nextBoardId);
	return nextBoardDto;
    }

    @RequestMapping(method = RequestMethod.POST, value = "/{currentBoardId}/{userId}/backward")
    @ResponseBody
    @SecurityInterception
    public BoardDto getDefaultBoardBackward(@PathVariable Long currentBoardId, @PathVariable Long userId, HttpServletRequest req,
	    HttpServletResponse resp) {
	Long priorBoardId = boardService.getPriorBoardId(currentBoardId, userId);
	BoardDto priorBoardDto = new BoardDto();
	priorBoardDto.setBoardId(priorBoardId);
	return priorBoardDto;
    }

    @RequestMapping(method = RequestMethod.POST, value = "/create")
    @ResponseBody
    @SecurityInterception
    public BoardDto createBoard(Board board, HttpServletRequest req, HttpServletResponse resp) {
	board = boardService.createBoard(board, sessionAttributes.getUserId(req));
	return mapper.map(board, BoardDto.class);
    }

    @RequestMapping(method = RequestMethod.POST, value = "/update")
    @ResponseBody
    @SecurityInterception
    public BoardDto updateBoard(BoardDto boardDto, HttpServletRequest req, HttpServletResponse resp) {
	Board board = mapper.map(boardDto, Board.class);
	board = boardService.updateBoard(board);
	return mapper.map(board, BoardDto.class);
    }

    @RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/activity/all")
    @ResponseBody
    @SecurityInterception
    public List<ActivityDto> getAllActivities(@PathVariable Long parentBoardId, HttpServletRequest req, HttpServletResponse resp) {
	List<Activity> activityList = activityService.getAllByBoardId(parentBoardId);
	List<ActivityDto> activityDtoList = new ArrayList<ActivityDto>();
	ActivityDto activityDto;
	for (Activity activity : activityList) {
	    activityDto = mapper.map(activity, ActivityDto.class);
	    activityDtoList.add(activityDto);
	}

	return activityDtoList;
    }

    @RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/activity/add")
    @ResponseBody
    @SecurityInterception
    public ActivityDto addActivityToBoard(@PathVariable Long parentBoardId, ActivityDto activityDto, HttpServletRequest req,
	    HttpServletResponse resp) {
	Activity activity = mapper.map(activityDto, Activity.class);
	activity = boardService.addActivityToBoard(parentBoardId, activity);
	return mapper.map(activity, ActivityDto.class);
    }

    @RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/contact/add/{userIdToAdd}")
    @ResponseBody
    @SecurityInterception
    public StatusDto addContactToBoard(@PathVariable Long parentBoardId, @PathVariable Long userIdToAdd, HttpServletRequest req,
	    HttpServletResponse resp) {
	User userToAdd = userService.getUser(userIdToAdd);
	StatusCodes statusCode = boardService.addContactToBoard(parentBoardId, userToAdd);
	return new StatusDto(statusCode.getStatusCode(), statusCode.getStatusText());
    }

    @RequestMapping(method = RequestMethod.POST, value = "{parentBoardId}/contact/remove/{userIdToRemove}")
    @ResponseBody
    @SecurityInterception
    public StatusDto removeContactFromBoard(@PathVariable Long parentBoardId, @PathVariable Long userIdToRemove, HttpServletRequest req,
	    HttpServletResponse resp) {
	StatusCodes statusCode = boardService.removeContactFromBoard(parentBoardId, userIdToRemove);
	return new StatusDto(statusCode.getStatusCode(), statusCode.getStatusText());
    }

    @RequestMapping(method = RequestMethod.GET, value = "/{parentBoardId}/contact/get")
    @ResponseBody
    @SecurityInterception
    @Transactional
    public UserDto[] getContacts(@PathVariable Long parentBoardId, HttpServletRequest req, HttpServletResponse resp) throws Exception {
	Board parentBoard = boardService.getBoardById(parentBoardId);

	List<UserDto> userDtoList = new ArrayList<UserDto>();
	for (User user : parentBoard.getBoardUser()) {
	    userDtoList.add(mapper.map(user, UserDto.class));
	}

	return userDtoList.toArray(new UserDto[] {});

    }

    @RequestMapping(method = RequestMethod.GET, value = "/{parentBoardId}/history/get")
    @ResponseBody
    @SecurityInterception
    @Transactional
    public HistoryDto[] getHistory(@PathVariable Long parentBoardId, HttpServletRequest req, HttpServletResponse resp) throws Exception {
	History[] historyArr = historyService.getFullBoardHistory(parentBoardId);

	List<HistoryDto> historyDtoList = new ArrayList<HistoryDto>();
	for (History history : historyArr) {
	    HistoryDto historyDto = mapper.map(history, HistoryDto.class);
	    User user = userService.getUser(history.getUserId());
	    historyDto.setNamensKuerzel(user.getNamensKuerzel());
	    historyDto.setHistoryActionValue(history.getHistoryAction().getActionIcon());

	    DateTime dateTime = new DateTime(history.getHistoryDate());
	    String formatedDate = DateTimeFormat.shortDateTime().print(dateTime.getMillis());
	    historyDto.setHistoryDateTime(formatedDate);

	    historyDtoList.add(historyDto);
	}

	return historyDtoList.toArray(new HistoryDto[] {});

    }

    public BoardService getBoardService() {
	return boardService;
    }

    public void setBoardService(BoardService boardService) {
	this.boardService = boardService;
    }

}
